#include "firmwareupgrader.h"
#include <QFile>
#include <QDataStream>
#include <QDebug>
#include <QThread>
#include <QTimer>

const unsigned short CRCTalbeAbs[] =
{
  0x0000, 0xCC01, 0xD801, 0x1400, 0xF001,\
  0x3C00, 0x2800, 0xE401, 0xA001, 0x6C00,\
  0x7800, 0xB401, 0x5000, 0x9C01, 0x8801,\
  0x4400,
};

FirmwareUpgrader::FirmwareUpgrader(QObject *parent)
    : QObject(parent), m_sequenceNumber(0), m_firmwareSize(0), m_totalSequence(0), m_retryCount(0), m_ackRequired(true), m_isUpgrading(false), m_deviceAddress(0x01)
{
    connect(&m_retryTimer, &QTimer::timeout, this, &FirmwareUpgrader::onRespondTimeout);
    m_retryTimer.setInterval(1000); // Set retry interval to 1 second
}

void FirmwareUpgrader::startUpgrade(const QString &filePath, quint8 deviceAddress)
{
    QFile firmwareFile(filePath);

    m_retryCount = 0;
    m_deviceAddress = deviceAddress; // Set device address

    if (!firmwareFile.open(QIODevice::ReadOnly))
    {
        qDebug() << "Failed to open firmware file.";
        emit upgradeFailed();
        return;
    }

    m_firmwareSize = firmwareFile.size();
    m_firmwareData = firmwareFile.readAll();
    firmwareFile.close();

    m_totalSequence = (m_firmwareSize-32)/PACKET_SIZE + ((m_firmwareSize%PACKET_SIZE)==0?0:1);  //除去第一包32字节

    quint16 crc = calculateCRC16(m_firmwareData.mid(32));
    emit crcCalculated(crc); // Emit CRC calculation signal

    m_isUpgrading = true;
    sendPacket(0); // Send the first packet with length and CRC
}

void FirmwareUpgrader::stopUpgrade()
{
    m_isUpgrading = false;
    m_retryTimer.stop();
    clearUpgrader();
}

void FirmwareUpgrader::sendPacket(int sequenceNumber)
{
    if (!m_isUpgrading) return; // Check if the upgrade process is still active

    QByteArray data;

    data.append(static_cast<char>(sequenceNumber >> 8)); // High byte
    data.append(static_cast<char>(sequenceNumber & 0xFF)); // Low byte
   
    if (sequenceNumber == 0) // First packet
    {
        data.append(m_firmwareData.left(32));
    }
    else
    {
        data.append(m_firmwareData.mid((sequenceNumber-1) * PACKET_SIZE+32, PACKET_SIZE));
    }

    QByteArray packet = creatorPack(m_deviceAddress, 0x11, data); // Use device address
    emit sendData(packet);

    // Update progress
    int progress = static_cast<int>((static_cast<double>(sequenceNumber * PACKET_SIZE) / m_firmwareSize) * 100);
    emit progressUpdated(progress);

    // Start a timer to send the query packet after 50ms
    QTimer::singleShot(100, this, &FirmwareUpgrader::sendQueryPacket);
}

void FirmwareUpgrader::sendQueryPacket()
{
    if (!m_isUpgrading) return; // Check if the upgrade process is still active

    if (m_ackRequired) 
    {
        QByteArray data;
        data.append(static_cast<char>(m_sequenceNumber >> 8)); // High byte
        data.append(static_cast<char>(m_sequenceNumber & 0xFF)); // Low byte

        QByteArray queryPacket = creatorPack(m_deviceAddress, 0x10, data); // Assuming address is 0x01
        emit sendData(queryPacket);

        // Start the retry timer
        m_retryTimer.start(); // Start the retry timer with the set interval
    }
    else
    {
        // Directly send the next packet if acknowledgment is not required
        if (m_sequenceNumber < m_totalSequence) 
        {
            m_sequenceNumber++;
            sendPacket(m_sequenceNumber);
        } 
        else 
        {
            emit progressUpdated(100); // Ensure progress reaches 100%
            qDebug() << "Upgrade completed successfully.";
            emit upgradeCompleted();
            clearUpgrader(); // Reset all attributes and variables
        }
    }
}

void FirmwareUpgrader::sendSoftResetCommand()
{
    QByteArray data;
    QByteArray packet = creatorPack(m_deviceAddress, 0x02, data); // Command 0x02 for soft reset
    emit sendData(packet);
}

void FirmwareUpgrader::sendUpgradeStateMachineResetCommand()
{
    QByteArray data;
    QByteArray packet = creatorPack(m_deviceAddress, 0x03, data); // Command 0x03 for upgrade state machine reset
    emit sendData(packet);
}

QByteArray FirmwareUpgrader::creatorPack(quint8 address, quint8 cmd, QByteArray data)
{
    QByteArray packet;
    quint16 frameLen = 6 + data.size();
    quint16 checksum;

    packet.append(0xaa);
    packet.append(0x55);
    packet.append(static_cast<char>(frameLen >> 8)); // High byte of length
    packet.append(static_cast<char>(frameLen & 0xff)); // Low byte of length
    packet.append(static_cast<char>(address));
    packet.append(static_cast<char>(cmd));
    packet.append(data);

    checksum = calculateChecksum(packet);
    packet.append(static_cast<char>(checksum >> 8)); // High byte of checksum
    packet.append(static_cast<char>(checksum & 0xff)); // Low byte of checksum

    return packet;
}

void FirmwareUpgrader::onRespondTimeout()
{
    if (!m_isUpgrading) return; // Check if the upgrade process is still active

    // Logic to handle MCU response and retry mechanism
    // If response is not correct, resend the last packet
    if (m_retryCount < 10)
    {
        m_retryCount++;
        sendPacket(m_sequenceNumber); // Resend the last packet
    }
    else
    {
        qDebug() << "Upgrade failed after 10 retries.";
        m_retryCount = 0;
        emit upgradeFailed();
        m_retryTimer.stop();
        clearUpgrader(); // Reset all attributes and variables
    }
}

void FirmwareUpgrader::parseSerialData(const QByteArray &data)
{
    if (!m_ackRequired) return; // Ignore if acknowledgment is not required

    // Stop the retry timer
    m_retryTimer.stop();

    // Process each packet in the received data
    int offset = 0;
    while (offset < data.size()) {
        int packetSize = (static_cast<quint8>(data[offset + 2]) << 8) | static_cast<quint8>(data[offset + 3]) + 4;
        QByteArray packet = data.mid(offset, packetSize);
        offset += packetSize;

        // Parse the response data using the protocol
        if (0 == parseProtocolData(packet))
        {
            m_retryCount = 0;
            if (m_sequenceNumber < m_totalSequence)
            {
                m_sequenceNumber++;
                sendPacket(m_sequenceNumber); // Send the next packet
            }
            else
            {
                emit progressUpdated(100); // Ensure progress reaches 100%
                qDebug() << "Upgrade completed successfully.";
                emit upgradeCompleted();
                clearUpgrader(); // Reset all attributes and variables
            }
        }
        else
        {
            m_retryTimer.start();
        }
    }
}

quint8 FirmwareUpgrader::parseProtocolData(const QByteArray &data)
{
    if (data.size() < 6) return false; // Minimum packet size

    if (static_cast<quint8>(data[0]) != 0xaa || static_cast<quint8>(data[1]) != 0x55)
        return false; // Invalid header

    quint16 length = (static_cast<quint8>(data[2]) << 8) | static_cast<quint8>(data[3]);
    if (data.size() != (length + 2)) return 0xff; // Length mismatch

    quint8 address = static_cast<quint8>(data[4]);
    quint8 cmd = static_cast<quint8>(data[5]);

    QByteArray payload = data.mid(6, length - 2);
    quint16 receivedChecksum = (static_cast<quint8>(data[length]) << 8) | static_cast<quint8>(data[length + 1]);
    quint16 calculatedChecksum = calculateChecksum(data.left(length));

    if(receivedChecksum != calculatedChecksum)
      return 0x02;
    
    return payload[0];
}

void FirmwareUpgrader::clearUpgrader()
{
    m_sequenceNumber = 0;
    m_firmwareSize = 0;
    m_totalSequence = 0;
    m_retryCount = 0;
    m_firmwareData.clear();
    m_isUpgrading = false;
}



quint16 FirmwareUpgrader::calculateCRC16(const QByteArray &data)
{
  quint16 crc = 0xFFFF; // Initial value
  for (char byte : data)
  {
    crc = CRCTalbeAbs[(byte ^ crc) & 0x0F] ^ (crc >> 4);
    crc = CRCTalbeAbs[((byte >> 4) ^ crc) & 0x0F] ^ (crc >> 4);
  }
    return crc;
}

quint16 FirmwareUpgrader::calculateChecksum(const QByteArray &data)
{
    quint16 checksum = 0;
    for (char byte : data)
    {
        checksum += static_cast<quint8>(byte);
    }
    return checksum;
}
